package com.digua.base.api

import com.alibaba.fastjson2.JSON
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ViewUtils
import com.digua.base.R
import com.digua.base.util.AuthorizeUtil
import com.digua.base.util.LogUtil
import com.digua.base.util.StrUtil
import com.digua.base.util.Toasts
import org.xutils.common.Callback
import org.xutils.common.Callback.CommonCallback
import org.xutils.ex.HttpException
import org.xutils.http.HttpMethod
import org.xutils.http.RequestParams
import org.xutils.x
import java.io.File


class ApiBase {
    companion object {
        private var resDataClz: Class<*>? = null
        private var dataField: String = "data"
        private var listField: String = "data"
        public var headers = mutableMapOf<String, String>()

        fun <T : ApiBaseBean> init(resBaseBeanClz: Class<T>, dataFieldName: String = "data", listFieldName: String = "data", headers: MutableMap<String, String> = mutableMapOf()) {
            resDataClz = resBaseBeanClz
            dataField = dataFieldName
            listField = listFieldName
            this.headers = headers
        }

        fun <T> req(isToast: Boolean, reqType: HttpMethod, apiUrl: String, params: Any?, listener: HttpReqListener<T>?) {
            val param = RequestParams(apiUrl)
            param.addHeader("content-type", "application/json")
            params?.let {
                val json = JSON.toJSONString(params)
                val map = (if (it is Map<*, *>) it else JSON.parse(json)) as Map<String, Any>
                map.keys.forEachIndexed { _, key -> param.addQueryStringParameter(key, map[key]) }
            }
            LogUtil.e("请求报文(${reqType})->${apiUrl}${params?.let { JSON.toJSONString(it) } ?: ""}")
            if (reqType == HttpMethod.POST) {
                x.http().post(param, handleResult(isToast, "(${reqType})->${apiUrl}", listener))
            } else if (reqType == HttpMethod.GET) {
                x.http().get(param, handleResult(isToast, "(${reqType})->${apiUrl}", listener))
            }
        }

        fun <T> reqJson(isToast: Boolean, reqType: HttpMethod, apiUrl: String, params: Any?, listener: HttpReqListener<T>?) {
            val param = RequestParams(apiUrl)
            param.addHeader("content-type", "application/json")
            headers.forEach { param.addHeader(it.key, it.value) }
            params?.let { param.bodyContent = JSON.toJSONString(params) }
            LogUtil.e("请求报文(${reqType})->${apiUrl}${params?.let { JSON.toJSONString(it) } ?: ""}")
            if (reqType == HttpMethod.POST) {
                x.http().post(param, handleResult(isToast, "(${reqType})->${apiUrl}", listener))
            } else if (reqType == HttpMethod.GET) {
                x.http().get(param, handleResult(isToast, "(${reqType})->${apiUrl}", listener))
            }
        }

        fun downloadFile(isToast: Boolean, downloadUrl: String, saveAbsolutePath: String, listener: DownloadListener?) {
            val params = RequestParams(downloadUrl)
            params.saveFilePath = saveAbsolutePath
            params.isAutoRename = true
            LogUtil.e("下载：-> $downloadUrl")
            x.http().get(params, object : Callback.ProgressCallback<File> {
                override fun onSuccess(result: File?) {
                    listener?.onSuccess(result)
                }

                override fun onError(ex: Throwable?, isOnCallback: Boolean) {
                    LogUtil.e("下载失败：-> $downloadUrl", ex)
                    if (isToast) Toasts.showShort(R.string.download_fail)
                    listener?.onError(ex, isOnCallback)
                }

                override fun onCancelled(cex: Callback.CancelledException?) {
                    LogUtil.e("下载取消：-> $downloadUrl", cex)
                    if (isToast) Toasts.showShort(R.string.download_cancel)
                    listener?.onCancelled(cex)
                }

                override fun onFinished() {
                    listener?.onFinished()
                }

                override fun onWaiting() {
                    listener?.onWaiting()
                }

                override fun onStarted() {
                    listener?.onStarted()
                }

                override fun onLoading(total: Long, current: Long, isDownloading: Boolean) {
                    LogUtil.e("下载进度：-> ${current}/${total} -> $downloadUrl")
                    listener?.onLoading(total, current, isDownloading)
                }
            })
        }

        fun <T> uploadFile(isToast: Boolean, apiUrl: String, file: File, listener: UploadFileListener<T>?): Callback.Cancelable {
            val params = RequestParams(apiUrl)
            params.isMultipart = true
            params.addBodyParameter("file", file)
            LogUtil.e("上传：-> $apiUrl")
            return x.http().post(params, object : CommonCallback<String> {
                override fun onSuccess(res: String) {
                    LogUtil.e("上传结果：-> $res")
                    val result = JSON.parseObject(res, resDataClz) as ApiBaseBean
                    if (result.isSuccess()) {
                        listener?.apply {
                            val jobj = JSON.parseObject(res)
                            val json = JSON.toJSONString(jobj[dataField])
                            val data: T = JSON.parseObject(if (StrUtil.isBlank(json) || json == "null") res else json, clz)
                            onSuccess(data)
                        } ?: { if (isToast) Toasts.showShort(R.string.operation_success) }
                    } else {
                        if (isToast) Toasts.showShort(result.resMsg())
                        listener?.onError(Throwable(result.resMsg()), true)
                    }
                    listener?.onSuccess(null)
                }

                override fun onError(ex: Throwable, isOnCallback: Boolean) {
                    LogUtil.e("上传失败：$apiUrl", ex)
                    if (isToast) Toasts.showShort(R.string.upload_fail)
                    listener?.onError(ex, isOnCallback)
                }

                override fun onCancelled(cex: Callback.CancelledException) {
                    LogUtil.e("取消上传：$apiUrl", cex)
                    if (isToast) Toasts.showShort(R.string.upload_cancel)
                    listener?.onCancelled(cex)
                }

                override fun onFinished() {
                    listener?.onFinished()
                }
            })
        }

        private fun <T> handleResult(isToast: Boolean, logHead: String, listener: HttpReqListener<T>?): CommonCallback<String> {
            return object : CommonCallback<String> {
                override fun onSuccess(res: String?) {
                    LogUtil.e("响应报文：${logHead}：${res}")
                    res?.let {
                        val result = JSON.parseObject(res, resDataClz) as ApiBaseBean
                        ViewUtils.runOnUiThread {
                            if (result.isSuccess()) {
                                if (AuthorizeUtil.checkHttp()) {
                                    listener?.apply {
                                        val jobj = JSON.parseObject(res)
                                        val field = if (isList) listField else dataField
                                        var json = if (field.isBlank()) res else JSON.toJSONString(jobj[field])
                                        if (isList) {
                                            if (StrUtil.isBlank(json) || json == "null") {
                                                json = JSON.toJSONString(jobj[dataField])
                                            }
                                            val datas = (JSON.parseArray(json, clz) ?: arrayListOf()) as ArrayList<T>
                                            onSuccess(datas)
                                            onSuccess(datas, result.total(), result.pageIndex(), result.pages())
                                        } else {
                                            val res = if (clz == String::class.java) jobj[field] as T else if (clz == resDataClz) result as T else JSON.parseObject(json, clz)
                                            if (res is ApiBaseBean) {
                                                if (res.isSuccess()) onSuccess(res)
                                                else {
                                                    if (isToast) Toasts.showShort(res.resMsg())
                                                    listener.fail(res.resMsg())
                                                }
                                            } else {
                                                onSuccess(res)
                                            }
                                        }
                                    } ?: { if (isToast) Toasts.showShort(R.string.operation_success) }
                                } else {
                                    listener?.fail(ActivityUtils.getTopActivity().getString(R.string.sys_busy_try))
                                }
                            } else {
                                if (isToast) Toasts.showShort(result.resMsg())
                                listener?.fail(result.resMsg())
                            }
                        }
                    }
                }

                override fun onError(ex: Throwable?, isOnCallback: Boolean) {
                    LogUtil.e("请求失败：${logHead}", ex)
                    if (ex is HttpException) {
                        ex.result?.let {
                            var result = if (it.startsWith("{")) JSON.parseObject(it, resDataClz) as ApiBaseBean else null
                            if (result == null) {
                                result = JSON.parseObject("{}", resDataClz) as ApiBaseBean?
                                result?.initBean(ex.code, ex.message ?: "")
                            }
                            if (result?.isSuccess() != true) {
                                ViewUtils.runOnUiThread {
                                    val msg = if (result!!.resMsg().isBlank()) ActivityUtils.getTopActivity().getString(R.string.sys_busy_try) else result.resMsg()
                                    if (isToast) Toasts.showShort(msg)
                                    listener?.fail(msg)
                                }
                            }
                        } ?: {
                            ViewUtils.runOnUiThread {
                                if (isToast) Toasts.showShort(R.string.sys_busy_try)
                                listener?.fail(ActivityUtils.getTopActivity().getString(R.string.sys_busy_try))
                            }
                        }
                    } else {
                        ViewUtils.runOnUiThread {
                            if (isToast) Toasts.showShort(R.string.sys_busy_try)
                            listener?.fail(ActivityUtils.getTopActivity().getString(R.string.sys_busy_try))
                        }
                    }
                }

                override fun onCancelled(cex: Callback.CancelledException?) {
                    LogUtil.e("请求取消：${logHead}", cex)
                    ViewUtils.runOnUiThread { listener?.fail(ActivityUtils.getTopActivity().getString(R.string.req_cancel)) }
                }

                override fun onFinished() {
                    ViewUtils.runOnUiThread { listener?.onFinished() }
                }
            }
        }
    }
}